#pragma once
#include <iostream>
#include <cstdlib>
#include <cstdbool>
using namespace std;

namespace YX
{
	template<class T>
	class CQueue
	{
	private:
		T* _ptr;
		size_t _head;
		size_t _tail;
		size_t _capacity;
	public:

		CQueue(size_t size)
			:_ptr(new T[size+1])
			,_head(0)
			,_tail(0)
			,_capacity(size+1)
		{}

		~CQueue()
		{
			delete[] _ptr;
		}

		CQueue(const CQueue<T>& cq)
			:_ptr(new T[cq._capacity])
			, _head(cq._head)
			, _tail(cq._tail)
			, _capacity(cq._capacity)
		{
			for (size_t i = 0; i < _capacity; i++)
			{
				_ptr[i] = cq._ptr[i];
			}
		}

		CQueue<T>& operator=(CQueue<T> cq)
		{
			std::swap(_ptr, cq._ptr);
			std::swap(_head, cq._head);
			std::swap(_tail, cq._tail);
			std::swap(_capacity, cq._capacity);

			return *this;
		}

		bool Empty()
		{
			return _head == _tail;
		}

		bool Full()
		{
			size_t next = (_tail + 1) % _capacity;

			return next == _head;
		}

		void Push(const T& val)
		{
			if (Full())
				return;

			_ptr[_tail] = val;
			_tail = (_tail + 1) % _capacity;
		}

		void Pop()
		{
			if (Empty())
				return;
			_head = (_head + 1) % _capacity;
		}

		T& Back()
		{
			if (Empty())
				exit(1);

			size_t prev = (_tail - 1) % _capacity;

			return _ptr[prev];
		}

		T& Front()
		{
			if (Empty())
				exit(1);

			return _ptr[_head];
		}

		size_t Size()
		{
			return (_capacity + _tail - _head) % _capacity;
		}

	};
}